C:\Users\Administrator>node -v
v12.18.2
C:\Users\Administrator>npm -v
6.14.5
npm install -g @vue/cli
C:\Users\Administrator>vue -V
@vue/cli 4.5.4
vue create demo
Vue CLI v4.5.4
? Please pick a preset: (Use arrow keys)
Default ([Vue 2] babel, eslint)
Default (Vue 3 Preview) ([Vue 3] babel, eslint)
> Manually select features
Vue CLI v4.5.4
? Please pick a preset: Manually select features
? Check the features needed for your project:
(*) Choose Vue version
(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
>(*) Router
( ) Vuex
( ) CSS Pre-processors
( ) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
Vue CLI v4.5.4
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, Router
? Choose a version of Vue.js that you want to start the project with
> 2.x
3.x (Preview)
history
模式?这里选 n ,因为使用history
后面打包后无法访问资源Vue CLI v4.5.4
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, Router
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) n
Vue CLI v4.5.4
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, Router
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
In package.json
Vue CLI v4.5.4
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, Router
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N) N
Vue CLI v4.5.4
✨ Creating project in C:\Users\Administrator\Desktop\test\demo.
� Initializing git repository...
⚙️ Installing CLI plugins. This might take a while...
> [email protected] postinstall C:\Users\Administrator\Desktop\test\demo\node_modules\core-js
> node -e "try{require('./postinstall')}catch(e){}"
> [email protected] postinstall C:\Users\Administrator\Desktop\test\demo\node_modules\ejs
> node ./postinstall.js
added 1203 packages from 900 contributors and audited 1206 packages in 130.865s
46 packages are looking for funding
run `npm fund` for details
found 1 high severity vulnerability
run `npm audit fix` to fix them, or `npm audit` for details
� Invoking generators...
� Installing additional dependencies...
added 4 packages from 1 contributor and audited 1210 packages in 16.169s
46 packages are looking for funding
run `npm fund` for details
found 1 high severity vulnerability
run `npm audit fix` to fix them, or `npm audit` for details
⚓ Running completion hooks...
� Generating README.md...
� Successfully created project demo.
� Get started with the following commands:
$ cd demo
$ npm run serve
C:\Users\Administrator\Desktop\test\demo>npm run serve
> [email protected] serve C:\Users\Administrator\Desktop\test\demo
> vue-cli-service serve
INFO Starting development server...
98% after emitting CopyPlugin
DONE Compiled successfully in 1553ms 11:47:13 ├F10: AM┤
App running at:
- Local: http://localhost:8080/
- Network: unavailable
Note that the development build is not optimized.
To create a production build, run npm run build.
npm install --save-dev electron
C:\Users\Administrator\Desktop\test\demo>npm install --save-dev electron
> [email protected] postinstall C:\Users\Administrator\Desktop\test\demo\node_modules\electron
> node install.js
Downloading electron-v9.2.1-win32-x64.zip: [=============================] 100% ETA: 0.0 seconds
+ [email protected]
added 3 packages from 8 contributors, updated 1 package and audited 1270 packages in 5888.384s
46 packages are looking for funding
run `npm fund` for details
found 1 high severity vulnerability
run `npm audit fix` to fix them, or `npm audit` for details
yarn add electron-builder --dev
C:\Users\Administrator\Desktop\test\demo>yarn add electron-builder --dev
yarn add v1.22.4
info No lockfile found.
warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
[1/4] Resolving packages...
warning @vue/cli-plugin-babel > @vue/cli-shared-utils > @hapi/[email protected]: joi is leaving the @hapi organization and moving back to 'joi' (https://github.com/sideway/joi/issues/2411)
warning @vue/cli-plugin-babel > @vue/cli-shared-utils > [email protected]: request has been deprecated, see https://github.com/request/request/issues/3142
warning @vue/cli-plugin-babel > @vue/cli-shared-utils > @hapi/joi > @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
warning @vue/cli-plugin-babel > @vue/cli-shared-utils > @hapi/joi > @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
warning @vue/cli-plugin-babel > @vue/cli-shared-utils > @hapi/joi > @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
warning @vue/cli-plugin-babel > @vue/cli-shared-utils > @hapi/joi > @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
warning @vue/cli-plugin-babel > @vue/cli-shared-utils > @hapi/joi > @hapi/topo > @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
warning @vue/cli-plugin-babel > @vue/cli-shared-utils > request > [email protected]: this library is no longer supported
warning @vue/cli-plugin-babel > webpack > watchpack > watchpack-chokidar2 > [email protected]: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.
warning @vue/cli-plugin-babel > webpack > watchpack > watchpack-chokidar2 > chokidar > [email protected]: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.
warning @vue/cli-plugin-babel > webpack > micromatch > snapdragon > source-map-resolve > [email protected]: https://github.com/lydell/resolve-url#deprecated
warning @vue/cli-plugin-babel > webpack > micromatch > snapdragon > source-map-resolve > [email protected]: Please see https://github.com/lydell/urix#deprecated
warning @vue/cli-service > webpack-dev-server > [email protected]: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.
[2/4] Fetching packages...
info [email protected]: The platform "win32" is incompatible with this module.
info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
info [email protected]: The platform "win32" is incompatible with this module.
info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 764 new dependencies.
info Direct dependencies
├─ @vue/[email protected]
├─ @vue/[email protected]
├─
.......
package.json
中main
入口,指向 electron 入口 js 文件,其他都是默认配置main.js
入口文件为文档中一致,暂时未做更改,后面再来调整const { app, BrowserWindow } = require('electron')
function createWindow () {
// 创建浏览器窗口
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// 并且为你的应用加载index.html
win.loadFile('index.html');
// 打开开发者工具
win.webContents.openDevTools()
}
// Electron会在初始化完成并且准备好创建浏览器窗口时调用这个方法
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(createWindow)
//当所有窗口都被关闭后退出
app.on('window-all-closed', () => {
// 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
// 否则绝大部分应用及其菜单栏会保持激活。
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// 在macOS上,当单击dock图标并且没有其他窗口打开时,
// 通常在应用程序中重新创建一个窗口。
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
// 您可以把应用程序其他的流程写在在此文件中
// 代码 也可以拆分成几个文件,然后用 require 导入。
loadURL
可直接加载 URL 连接,那么就有了下面的思路。main.js
文件,实现直接加载 Vue 服务地址function createWindow () {
// 创建浏览器窗口
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// 修改为加载 Vue 服务地址
win.loadURL('http://localhost:8080/');
// 打开开发者工具
win.webContents.openDevTools()
}
package.json
中添加一条脚本,先启动 Vue 服务,然后运行 Electron,在 scripts 中添加了一条 electron-dev
脚本"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"electron-dev": "vue-cli-service serve && electron ."
},
vue-cli-service serve
后,因为脚本未终止,根本执行不到后面的 electron .
,所以导致没办法启动 Electronelectron .
vue-cli-service serve
和 electron .
const {exec} = require('child_process');
// 定义进程
// vue 服务进程
let dev_vue_process = null;
// electron 服务进程
let dev_electron_process = null;
init()
// 启动服务
function init() {
// 启动Vue服务
if(dev_vue_process == null){
// 执行启动 Vue 服务命令
dev_vue_process = exec('vue-cli-service serve',{});
dev_vue_process.stdout.on('data', data => {
electronLog(data)
// 当 Vue 执行输出 http 访问连接时判断启动成功
if(data.indexOf("http") > -1){
// 启动 electron
startElectron()
}
})
dev_vue_process.stderr.on('data', data => {
if(data.indexOf("<s> [webpack.Progress]") < 0){
electronLog(data)
}
})
}
}
// 启动 electron
function startElectron() {
if(dev_electron_process == null){
// 执行 electron 入口为 package.json 中配置的 main 属性
dev_electron_process = exec('electron .',{});
dev_electron_process.stdout.on('data', data => {
console.log(data)
})
dev_electron_process.stderr.on('data', data => {
console.log(data)
})
dev_electron_process.on('close', () => {
// 进程关闭时退出
process.exit()
})
}
}
// 打印日志
function electronLog (data) {
let log = ''
data = data.toString().split(/\r?\n/)
data.forEach(line => {
log += ` ${line}\n`
})
if (/[0-9A-z]+/.test(log)) {
console.log(
'┏ Electron -------------------' +
'\n\n' +
log +
'┗ ----------------------------' +
'\n'
)
}
}
package.js
文件中的执行命令 electron-dev
使用 node 来执行我们刚才创建的 js 配置文件"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"electron-dev": "node electron/config/electron-run-dev.js"
},
electron-dev
命令,可以看得出已经成功了!✌✌✌About.vue
添加一个按钮点击打开一个新的 electron 窗口<template>
<div class="about">
<h1>This is an about page</h1>
<button @click="clickButton">点击查看</button>
</div>
</template>
<script> const electron = require('electron')
// import electron from 'electron'
export default {
methods:{
clickButton(){
new electron.remote.BrowserWindow({
width: 200,
height: 200
}).loadURL('http://baidu.com')
}
}
} </script>
require
、import
进行引入,都报错const electron = require('electron')
import electron from 'electron'
TypeError: fs.existsSync is not a function
at getElectronPath (index.js?bdb9:7)
at Object.eval (index.js?bdb9:18)
at eval (index.js:20)
at Object../node_modules/electron/index.js (about.js:34)
at __webpack_require__ (app.js:854)
at fn (app.js:151)
at eval (About.vue?c330:9)
at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/About.vue?vue&type=script&lang=js& (about.js:11)
at __webpack_require__ (app.js:854)
at fn (app.js:151)
window.require
来代替 require
进行导入,试一试,果然可行!这一步的前提是在 electron 入口 js 中,创建窗口时需要将 nodeIntegration
设置为 true,默认是 false 的<template>
<div class="about">
<h1>This is an about page</h1>
<button @click="clickButton">点击查看</button>
</div>
</template>
<script> const electron = window.require('electron')
export default {
methods:{
clickButton(){
new electron.remote.BrowserWindow({
width: 200,
height: 200
}).loadURL('http://baidu.com')
}
}
} </script>
<template>
<div class="about">
<h1>This is an about page</h1>
<button @click="clickButton">点击查看</button>
</div>
</template>
<script> export default {
data(){
return{
electron : window.require('electron')
}
},
methods:{
clickButton(){
new this.electron.remote.BrowserWindow({
width: 200,
height: 200
}).loadURL('http://baidu.com')
}
}
} </script>
your-app/
├── package.json
├── main.js
└── index.html
package.json
、main.js
、index.html
package.json
与我们写的不一样,可能是在 build 的时候,他自动重新生成的一个。main.js
、index.html
main.js
:electron 入口文件index.html
:electron 需要加载的页面
main.js
electron 入口文件我们是有的,但是缺少 html 加载页面,所以我们还是得必须先把 Vue 进行 build 后,然后把main.js
放到一起去进行打包,当然main.js
就需要加载 Vue 进行 build 后的 index.html 页面了。vue.config.js
module.exports = {
// 这个值也可以被设置为相对路径 ('./'),这样所有的资源都会被链接为相对路径,这样打出来的包可以被部署在任意路径。
publicPath: './',
// 输出文件目录
outputDir: 'build/vue-build'
}
package.json
中配置,增加了 electron-build
脚本命令 和 build
相关配置,electron-builder --dir
:electron-builder 的一个打包命令,不用生成安装包build
:electron-builder 中的一个配置项,具体参数可阅读 electron-builder 文档,其中特别说明下output
:electron 打包到指定的路径files
:具体打包那些文件夹的内容{
"name": "demo",
"version": "0.1.0",
"private": true,
"main": "build/vue-build/main.js",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"electron-dev": "node electron/config/electron-run-dev.js",
"electron-build": "electron-builder --dir"
},
"build": {
"productName": "vue-cli-electron",
"appId": "com.test",
"asar": false,
"directories": {
"output": "build/electron-build"
},
"files": [
"build/vue-build/**/*"
]
},
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.2.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"electron": "^9.2.1",
"electron-builder": "^22.8.0",
"vue-template-compiler": "^2.6.11"
}
}
main.js
放到 build/vue-build 中,然后执行 electron 的打包操作mian.js
中 loadURL 改为加载本地的 index.html ,loadURL 也能加载本地页面,但需要在前面加上 file://
,这里使用了 path 模块来拼接路径,如果直接使用下面两个方式是不行的。// 因为 electron 打包好后只会去对应文件夹 resources/app 中找 index.html
// 因为我们的index.html 在 build/vue-build 下面
win.loadFile("index.html");
// 这样写是可行的
win.loadFile("build/vue-build/index.html");
// 这样肯定也不行的,这样只会去系统盘根目录下去找 index.html
win.loadURL(path.join("file://", 'index.html'));
__dirname
来做路径拼接__dirname
:当前文件的所在绝对路径,如下所示进行拼接
// 会去 `main.js ` 所在路径找 index.html
win.loadURL(path.join("file://", __dirname, 'index.html'));
package.json
中的 main
入口文件,因为现在要打包,所以得把入口文件也改成 build/vue-build 中的 main.js
electron-build
看下打包情况与运行情况,目前是没有问题的。如果打包慢,下载对应依赖很慢的话,可以参考 《electron-builder 打包下载依赖慢》这篇文章main.js
中增加判断如下process.env.NODE_ENV
来判断是使用开发时的 Url,还是发布后本地的 index.html,但是 process.env.NODE_ENV
是未定义的,所以我们得在自己的脚本中定义const { app, BrowserWindow } = require('electron')
const path = require('path')
// 获取指定加载路径
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9999`
: path.join("file://", __dirname, 'index.html')
function createWindow () {
// 创建浏览器窗口
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// 并且为你的应用加载index.html
win.loadURL(winURL);
// 打开开发者工具
win.webContents.openDevTools()
}
// Electron会在初始化完成并且准备好创建浏览器窗口时调用这个方法
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(createWindow)
//当所有窗口都被关闭后退出
app.on('window-all-closed', () => {
// 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
// 否则绝大部分应用及其菜单栏会保持激活。
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// 在macOS上,当单击dock图标并且没有其他窗口打开时,
// 通常在应用程序中重新创建一个窗口。
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
// 您可以把应用程序其他的流程写在在此文件中
// 代码 也可以拆分成几个文件,然后用 require 导入。
JsonUpUtil.js
脚本,用于更改 package.json
中的入口文件路径const fs = require('fs');
const path = require('path')
let packageJson = {}
/**
* 修改指定Json文件
* @param jsonFile 文件路径
* @param key 需要修改的key
* @param newVal 新的值
*/
function changeJson(jsonFile, key, newVal) {
packageJson = {};
jsonFile = path.join(__dirname, jsonFile);
fs.readFile(jsonFile, (err, data) => {
if (err) {
console.error(err);
}
// 获取json文件数据
packageJson = data.toString();
packageJson = JSON.parse(packageJson);
if(packageJson[key] != newVal){
// 修改对应Key
packageJson[key] = newVal;
// 保存到文件
let newJson = JSON.stringify(packageJson, null, "\t");
fs.writeFile(jsonFile, newJson, function (err) {
if (err) {
console.error(err);
}
})
}
});
}
module.exports = {
changeJsonMain: (val) => {
console.log("程序入口:", val)
changeJson('../../../package.json', 'main', val)
}
}
electron-build-pro.js
脚本process.env.NODE_ENV
为生产发布package.json
中 main
入口改为 我们复制到 build/vue-build 中的 main.jsconst fs = require('fs')
const path = require('path')
const jsonUp = require('./util/JsonUpUtil')
// 发布正式环境配置
process.env.NODE_ENV = 'production';
// 修改package.json为发布环境入口
jsonUp.changeJsonMain('build/vue-build/main.js');
// 将 electron-dev 目录中的所有文件复制到 build/vue-build 目录中一起打包
exists(path.join(__dirname, '../dev'), path.join(__dirname, '../../build/vue-build'), copy );
/**
* 复制目录中的所有文件包括子目录
* @param src 需要复制的目录
* @param dst 复制到指定的目录
*/
function copy(src, dst) {
// 读取目录中的所有文件/目录
fs.readdir(src, (err, paths)=> {
if (err) {
throw err;
}
paths.forEach(function (path) {
let _src = src + '/' + path,
_dst = dst + '/' + path,
readable, writable;
fs.stat(_src, function (err, st) {
if (err) {
throw err;
}
// 判断是否为文件
if (st.isFile()) {
// 创建读取流
readable = fs.createReadStream(_src);
// 创建写入流
writable = fs.createWriteStream(_dst);
// 通过管道来传输流
readable.pipe(writable);
}
// 如果是目录则递归调用自身
else if (st.isDirectory()) {
exists(_src, _dst, copy);
}
});
});
});
}
// 判断该目录是否存在,不存在需要先创建目录
function exists(src, dst, callback) {
fs.exists(dst, function (exists) {
// 已存在
if (exists) {
callback(src, dst);
}
// 不存在
else {
fs.mkdir(dst, function () {
callback(src, dst);
});
}
});
}
electron-build-pro.js
中我们都定义了process.env.NODE_ENV
,开发环境脚本electron-run-dev.js
肯定也需要定义,来进行区分开发环境还是发布环境process.env.NODE_ENV
为开发环境package.json
调整为 开发环境const {exec} = require('child_process');
const jsonUp = require('./util/JsonUpUtil')
// 开发环境配置
process.env.NODE_ENV = 'development';
// 修改package.json为开发环境入口
jsonUp.changeJsonMain('electron/dev/main.js');
// 定义进程
// vue 服务进程
let dev_vue_process = null;
// electron 服务进程
let dev_electron_process = null;
init()
// 启动服务
function init() {
// 启动Vue服务
if(dev_vue_process == null){
// 执行启动 Vue 服务命令
dev_vue_process = exec('vue-cli-service serve',{});
dev_vue_process.stdout.on('data', data => {
electronLog(data)
// 当 Vue 执行输出 http 访问连接时判断启动成功
if(data.indexOf("http") > -1){
// 启动 electron
startElectron()
}
})
dev_vue_process.stderr.on('data', data => {
if(data.indexOf("<s> [webpack.Progress]") < 0){
electronLog(data)
}
})
}
}
// 启动 electron
function startElectron() {
if(dev_electron_process == null){
// 执行 electron 入口为 package.json 中配置的 main 属性
dev_electron_process = exec('electron .',{});
dev_electron_process.stdout.on('data', data => {
console.log(data)
})
dev_electron_process.stderr.on('data', data => {
console.log(data)
})
dev_electron_process.on('close', () => {
// 进程关闭时退出
process.exit()
})
}
}
// 打印日志
function electronLog (data) {
let log = ''
data = data.toString().split(/\r?\n/)
data.forEach(line => {
log += ` ${line}\n`
})
if (/[0-9A-z]+/.test(log)) {
console.log(
'┏ Electron -------------------' +
'\n\n' +
log +
'┗ ----------------------------' +
'\n'
)
}
}
package.json
中修改 electron-build
打包命令,使用刚创建的 electron-build-pro.js
进行打包操作electron-build-pro.js
脚本 -> electron 打包"scripts": {
"vue:serve": "vue-cli-service serve",
"vue:build": "vue-cli-service build",
"electron:dev": "node electron/config/electron-run-dev.js",
"electron:build": "vue-cli-service build && node electron/config/electron-build-pro.js && electron-builder --dir"
}
electron-dev
进行开发,和使用 electron-build
进行打包了。electron-build-pro.js
中,会将 electron -> dev 下面的所有文件夹和文件复制到 build/vue-build 里面一并打包,所以 跟 electron 相关的开发都可以在 electron -> dev 目录下进行开发。相关 Demo 项目我已上传到 GitHub ,有兴趣的可以看下,毕竟我不是专业前端,突发奇想的来了解了下,有任何建议的小伙伴欢迎留言,互相学习!
Demo 项目:vue-cli-electron